{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# XYZ, a Now Python-Friendly <br/>Geospatial Data Management Service "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p style=\"color:black;font-size:18px;\">\n",
    "<strong>Dinu Gherman, <a href=\"https://here.com/\">HERE Technologies</a><br/>\n",
    "<a href=\"http://2020.geopython.net\">Online Python Machine Learning Conference &amp; GeoPython 2020</a><br />Sept. 21, 2020</strong></p>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction\n",
    "\n",
    "**HERE.com:** the location company, growing beyond automotive/logistics, 30+ years experience\n",
    "\n",
    "**XYZ:** a new, unified, accessible, scalable, managed, open geo-database\n",
    "\n",
    "**Components:** Hub, REST API, CLI, Studio (Web-Viewer)\n",
    "\n",
    "**Features:** Open Source, Geospatial database/service, large volume, cloud, real-time, now Python.\n",
    "\n",
    "**This talk:** about using XYZ programmatically from Python as intended for data scientists/analysts."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Key Concepts\n",
    "\n",
    "**XYZ:** Hub, Spaces with IDs, Features (geometry data) with IDs, Tags, Properties\n",
    "\n",
    "**Spaces:** Create, read, list, update, share, delete. Plus info and stats\n",
    "\n",
    "**Features:** Add, read, update, iterate, search, cluster (hex/quad bins), delete\n",
    "\n",
    "**Search:** Features by ID, tag, property, bbox, tile, radius or geometry\n",
    "\n",
    "**[XYZ-Spaces-Python](https://github.com/heremaps/xyz-spaces-python)**, short `xyzspaces`:\n",
    "\n",
    "- wraps the XYZ Hub RESTful API\n",
    "- provides a higher-level `Space` class \n",
    "- imports GeoJSON, plus CSV, GeoBuff, GPX, KML, WKT, Shapefiles, and GeoPandas dataframes\n",
    "\n",
    "**Pro plan (supported):** Virtual spaces, feature clustering, activity log (plus more to come)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Mini-Tutorial\n",
    "\n",
    "This section gives a short overview of basic interaction patterns with the HERE Data Hub (based on XYZ Hub, with some pro features added)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "import os\n",
    "from IPython.display import JSON\n",
    "\n",
    "import geojson\n",
    "import pandas as pd\n",
    "import requests\n",
    "import turfpy.measurement\n",
    "from branca.colormap import linear\n",
    "from ipyleaflet import basemaps, GeoJSON, LayersControl, Map, Polygon\n",
    "from ipywidgets import interact\n",
    "\n",
    "import xyzspaces\n",
    "import xyzspaces.datasets\n",
    "from xyzspaces.apis import HubApi\n",
    "from xyzspaces import XYZ"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xyz_token = os.getenv(\"XYZ_TOKEN\")\n",
    "xyz = XYZ(credentials=xyz_token)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### List spaces"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sp_list = xyz.spaces.list()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(sp_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sp = sp_list[0]\n",
    "JSON(sp)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create a space\n",
    "\n",
    "`XYZ.spaces.new()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data1 = xyzspaces.datasets.get_countries_data()\n",
    "JSON(data1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m = Map(center=[0, 0], zoom=1)\n",
    "m.layout.height = \"300px\"\n",
    "m += GeoJSON(data=data1)\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "world_space = xyz.spaces.new(title=\"PyML & GeoPy 2020 Demo\", description=\"Demo\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "world_space.info"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sp_id = world_space.info[\"id\"]\n",
    "sp_id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "world_space.get_statistics()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Add features\n",
    "\n",
    "`space.add_features()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "features_info = world_space.add_features(features=data1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "world_space.get_statistics()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Access features\n",
    "\n",
    "`space.iter_feature()`, `space.get_feature()`, `space.get_features()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m = Map(center=[0, 0], zoom=1)\n",
    "m.layout.height = \"300px\"\n",
    "data2 = geojson.FeatureCollection(list(world_space.iter_feature()))\n",
    "m += GeoJSON(data=data2)\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "JSON(data1[\"features\"][0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "JSON(data2[\"features\"][0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`api.get_space_feature()`, `space.get_feature()`..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "api = HubApi(credentials=xyz_token)\n",
    "JSON(api.get_space_feature(sp_id, \"AFG\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using more convenient abstractions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "afg = world_space.get_feature(\"AFG\")\n",
    "JSON(afg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m = Map(center=[30, 70], zoom=3)\n",
    "m.layout.height = \"300px\"\n",
    "m += GeoJSON(data=afg)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Multiple features:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "JSON(world_space.get_features([\"AFG\", \"IND\"]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Delete space"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# world_space.delete()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Update features, add tags\n",
    "\n",
    "`space.update_feature`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for feat in world_space.iter_feature():\n",
    "    name = feat[\"properties\"][\"name\"].lower()\n",
    "    if name[0] == name[-1]:\n",
    "        world_space.update_feature(feature_id=feat[\"id\"], \n",
    "                             data=feat, \n",
    "                             add_tags=[\"palindromish\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Search features with tags\n",
    "\n",
    "`space.search()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for feat in world_space.search(tags=[\"palindromish\"]):\n",
    "    print(feat[\"properties\"][\"name\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Search features in bounding box"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`space.features_in_bbox()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Features in the Southern hemishpere:\n",
    "m = Map(center=[-20, 0], zoom=1)\n",
    "m.layout.height = \"300px\"\n",
    "feats = list(world_space.features_in_bbox([-180, -90, 180, 0], clip=False))\n",
    "m += GeoJSON(data=geojson.FeatureCollection(feats))\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Search features by geometry\n",
    "\n",
    "`space.spatial_search_geometry()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "deu = world_space.get_feature(\"DEU\")\n",
    "del deu[\"geometry\"][\"bbox\"]  # hack"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m = Map(center=[50, 9], zoom=4)\n",
    "feats = list(world_space.spatial_search_geometry(data=deu[\"geometry\"]))\n",
    "m += GeoJSON(data=geojson.FeatureCollection(feats))\n",
    "m += GeoJSON(data=deu, style={\"color\": \"red\", \"fillOpacity\": 0})\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "eu_feats = list(world_space.features_in_bbox([-20, 38, 35, 70]))\n",
    "list(sorted([feat[\"properties\"][\"name\"] for feat in eu_feats]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.DataFrame(data=[{\n",
    "    \"Name\": eu_feat[\"properties\"][\"name\"],\n",
    "    \"Neighbors\":\n",
    "        len(list(world_space.spatial_search_geometry(data=eu_feat[\"geometry\"]))) - 1}\n",
    "    for eu_feat in eu_feats\n",
    "]).sort_values(by=[\"Neighbors\", \"Name\"], ascending=False, axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.index = df.Name\n",
    "df.plot.bar(title=\"#Neighboring Countries in Europe\", figsize=(10, 5), xlabel='')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Search features by tags/parameters\n",
    "\n",
    "`space.search()`\n",
    "\n",
    "Now using the Microsoft US Building Footprints [dataset](https://github.com/Microsoft/USBuildingFootprints) (ca. 125 M buildings), also available in a HERE Data Hub space (ID: R4QDHvd1), used in this simple [ZIP code example](https://studio.here.com/viewer/?project_id=58604429-3919-437d-8ae4-9ee9693104d1) on [HERE Studio](https://studio.here.com)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from xyzspaces.datasets import get_microsoft_buildings_space as msbs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ms_space = msbs()\n",
    "JSON(ms_space.get_statistics())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lat, lon = 38.89759, -77.03665  # White House, USA\n",
    "m = Map(center=[lat, lon], zoom=18)\n",
    "feats = list(ms_space.search(tags=[\"postalcode@20500\"]))\n",
    "# feats = list(space.spatial_search(lat=lat, lon=lon, radius=100))  # same\n",
    "m += GeoJSON(data=geojson.FeatureCollection(feats))\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "JSON(feats[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Compared with original feature from https://github.com/Microsoft/USBuildingFootprints:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "JSON({\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-77.037293,38.897578],[-77.036459,38.897577],[-77.036459,38.897592],[-77.035855,38.897591],[-77.035856,38.897546],[-77.035778,38.897545],[-77.035778,38.897399],[-77.03549,38.897399],[-77.035489,38.897735],[-77.03556,38.897735],[-77.03556,38.897771],[-77.035783,38.897771],[-77.035783,38.897706],[-77.036228,38.897707],[-77.036228,38.897817],[-77.036439,38.897818],[-77.036438,38.897928],[-77.036619,38.897929],[-77.036619,38.89781],[-77.036853,38.89781],[-77.036853,38.897708],[-77.03695,38.897708],[-77.03695,38.897708],[-77.037851,38.897709],[-77.037851,38.89747],[-77.037929,38.89747],[-77.037929,38.897427],[-77.037815,38.897427],[-77.037816,38.897339],[-77.037294,38.897338],[-77.037293,38.897578]]]},\"properties\":{}})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gen = ms_space.search(params={\"p.city\": \"Washington\"})\n",
    "wash_dc_1000 = [next(gen) for i in range(1000)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lat, lon = 38.89759, -77.03665  # White House, USA\n",
    "m = Map(center=[lat, lon], zoom=11, basemap=basemaps.CartoDB.Positron)\n",
    "m += GeoJSON(data=geojson.FeatureCollection(wash_dc_1000))\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Search features by radius\n",
    "\n",
    "`space.spatial_search()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lat, lon = 38.89759, -77.03665  # White House, USA\n",
    "m = Map(center=[lat, lon], zoom=14, basemap=basemaps.CartoDB.Positron)\n",
    "features = list(ms_space.spatial_search(lat=lat, lon=lon, radius=2000))\n",
    "m += GeoJSON(data=geojson.FeatureCollection(features))\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "area = turfpy.measurement.area\n",
    "sizes = [area(f) for f in features]\n",
    "cm = linear.Oranges_04.scale(min(sizes), max(sizes))\n",
    "cm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lat, lon = 38.89759, -77.03665  # White House, USA\n",
    "m = Map(center=[lat, lon], zoom=14, basemap=basemaps.CartoDB.Positron)\n",
    "features = list(ms_space.spatial_search(lat=lat, lon=lon, radius=2000))\n",
    "m += GeoJSON(\n",
    "    data=geojson.FeatureCollection(features),\n",
    "    hover_style={\"fillOpacity\": 1},\n",
    "    style_callback=lambda feat: {\"weight\": 2, \"color\": cm(area(feat))}\n",
    ")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "See also a more expanded version using building house numbers in this notebook on GitHub: [docs/notebooks/building_numbers.ipynb](https://github.com/heremaps/xyz-spaces-python/blob/master/docs/notebooks/building_numbers.ipynb)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ms_space.delete()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Cluster all space features\n",
    "\n",
    "`space.cluster()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "xyz_pro_token = os.getenv(\"XYZ_PRO_TOKEN\")\n",
    "xyz = XYZ(credentials=xyz_pro_token)\n",
    "cluster_space = xyz.spaces.new(title=\"Cluster Demo GeoPy\", description=\"...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "info = cluster_space.add_feature(afg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lat, lon = list(reversed(turfpy.measurement.center(afg)[\"geometry\"][\"coordinates\"]))\n",
    "m = Map(center=[lat, lon], zoom=4, basemap=basemaps.CartoDB.Positron)\n",
    "m += GeoJSON(data=afg, name=\"AFG\", style={\"color\": \"red\"})\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@interact(abs_res=(0, 4))\n",
    "def overlay(abs_res=0):\n",
    "    global m\n",
    "    fc = cluster_space.cluster(\n",
    "        \"hexbin\",\n",
    "        clustering_params = {\"absoluteResolution\": abs_res}\n",
    "    )\n",
    "    lay = GeoJSON(data=fc, name=f\"Hexbin {abs_res}\")\n",
    "    try:\n",
    "        prev = [l for l in m.layers if l.name.startswith(\"Hexbin\")][0]\n",
    "        m.substitute_layer(prev, lay)\n",
    "    except IndexError:\n",
    "        m += lay"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cluster_space.delete_feature(\"AFG\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`space.add_features_csv()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# https://ourairports.com/data/\n",
    "# https://ourairports.com/data/airports.csv\n",
    "url = \"https://ourairports.com/data/airports.csv\"\n",
    "fn = os.path.basename(url)\n",
    "try:\n",
    "    df = pd.read_csv(fn)\n",
    "except:\n",
    "    df = pd.read_csv(url)\n",
    "    df.to_csv(fn, index=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df1 = df[df.continent==\"EU\"]\n",
    "df1 = df1[df1.iso_country!=\"RU\"]\n",
    "fn = \"airports_eu.csv\"\n",
    "df1.to_csv(fn, index=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m = Map(center=[50, 13], zoom=3, basemap=basemaps.CartoDB.Positron)\n",
    "m += LayersControl(position=\"topright\")\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# add many single point XYZ feature from CSV file\n",
    "info = cluster_space.add_features_csv(fn, \"longitude_deg\", \"latitude_deg\", id_col=\"id\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# calculate clustered cells\n",
    "fcc = cluster_space.cluster(\"hexbin\", clustering_params={\"absoluteResolution\": 2})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# add hex cluster cells to map\n",
    "values = [f[\"properties\"][\"aggregation\"][\"qty\"]\n",
    "          for f in fcc[\"features\"]]\n",
    "cm = linear.Oranges_04.scale(min(values), max(values))\n",
    "m += GeoJSON(data=fcc,\n",
    "             name=\"Hex Clusters\",\n",
    "             hover_style={\"fillOpacity\": 0.75},\n",
    "             style_callback=lambda feat: {\n",
    "                 \"color\": cm(feat[\"properties\"][\"aggregation\"][\"qty\"])\n",
    "             })"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# build one multi-point GeoJSON object\n",
    "coords = [[tup.longitude_deg, tup.latitude_deg] for tup in df1.itertuples()]\n",
    "mp = geojson.MultiPoint([[lon, lat] for [lon, lat] in coords])\n",
    "f = geojson.Feature(geometry=mp)\n",
    "f[\"id\"] = \"airports\"\n",
    "fc = geojson.FeatureCollection([f])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m += GeoJSON(data=fc, \n",
    "             name=\"Airports\",\n",
    "             point_style={'radius': 1, \"weight\": 1, \"fillOpacity\": 1})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Cleanup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cluster_space.delete()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "world_space.delete()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "More examples are available in the [docs/notebooks](github.com/heremaps/xyz-spaces-python) folder on GitHub."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Not shown...\n",
    "\n",
    "- Search by tiles\n",
    "- Schema validation (pro)\n",
    "- Virtual spaces (pro)\n",
    "- Activity log (pro)\n",
    "- Rule-based tags (pro)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusions\n",
    "\n",
    "### Main take-aways\n",
    "\n",
    "XYZ:\n",
    "\n",
    "- is an Open Source geospatial cloud database/service\n",
    "- is the foundation of the HERE Data Hub (commercial, free plan w/o CC)\n",
    "- stores geodata features as GeoJSON, organized in *spaces*\n",
    "- allows to manage, scale and filter geodata easily\n",
    "- loves Python: `pip install xyzspaces`, also on conda-forge\n",
    "- wants you to engage and give feedback!\n",
    "\n",
    "### Links\n",
    "\n",
    "- https://here.xyz\n",
    "- https://github.com/heremaps/xyz-spaces-python\n",
    "- https://developer.here.com/products/data-hub\n",
    "\n",
    "### Questions?"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  },
  "toc-autonumbering": false,
  "toc-showcode": false,
  "toc-showmarkdowntxt": false,
  "toc-showtags": false
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
